class AKFPlayer extends AKFPC;

// Free Aim Area variables


var bool bHudLocksPlayerRotation;

// new free-aim
//var		rotator		RecoilRotator;					// Stores recoil added to the free-aim buffer
//var		float		LastRecoilTime;                 // Last time we got recoil
//var		float		RecoilSpeed;					// The amount of time it will take to process this recoil
var		int			FreeAimMaxYawLimit;				// Maximum yaw rotation of the weapon in free-aim mode
var		int			FreeAimMinYawLimit;             // Minimum yaw rotation of the weapon in free-aim mode
var		int			FreeAimMaxPitchLimit;           // Maximum pitch rotation of the weapon in free-aim mode
var		int			FreeAimMinPitchLimit;           // Minimum pitch rotation of the weapon in free-aim mode

var		float		FAAWeaponRotationFactor;		// FA rotation factor for weapons in their buffer box
var		float		LastFreeAimSuspendTime;			// Used in smoothing out transitions to/from free-aim

var		int 		YawTweenRate;					// Yaw return to center speed when not using free-aim  = FreeAimMaxYawLimit/NumSecondsToTween(0.25)
var		int 		PitchTweenRate;                 // Pitch return to center speed when not using free-aim  = FreeAimMaxPitchLimit/NumSecondsToTween(0.25)

// Weapon Sway
var		bool		bSway;	                        // Weapon sway is enabled
var     float       baseSwayYawAcc;                 // base rate of vertical sway acc
var     float       baseSwayPitchAcc;               // base rate of horizontal sway acc
var     float       SwayPitch;
var     float       SwayYaw;
var     float       WeaponSwayYawRate;
var     float       WeaponSwayPitchRate;
var     float       SwayTime;
var()	InterpCurve	SwayCurve;		 				// The amount of sway to apply based on an input time in ironsights
var 	float		SwayClearTime;
const   SwayElasticFactor = 3.0; 					// is ( 0.002 *   baseSwayYawAcc)
const   SwayDampingFactor = 0.1732;					// dampingFactor = 0.1*sqrt(elasticFactor); // underdamped damping, smoother sway; 0.5*sqrt(elasticFactor) is critically damped


// This is to capture mouse input on the situation map
var     bool        bHudCapturesMouseInputs;
//var     bool        bHudLocksPlayerRotation;
var     vector      PlayerMouse;






// most of this code comes from UDN:
// https://udn.epicgames.com/Two/MouseCursorInterface
simulated function HandleMousePlayerMove(float DeltaTime)
{
    local vector MouseV;

    // calc mouse position offset
    MouseV.X = DeltaTime * aMouseX / (InputClass.default.MouseSensitivity * DesiredFOV * 0.01111);
    MouseV.Y = DeltaTime * aMouseY / (InputClass.default.MouseSensitivity * DesiredFOV * -0.01111);

    // update mouse position
    PlayerMouse += MouseV;

    // notify hud of new mouse position
    SmartHud(myHUD).MouseInterfaceUpdatePosition(PlayerMouse);
}

simulated function HandleMouseClick()
{
    SmartHud(myHUD).MouseInterfaceClick();
}

simulated function MouseInterfaceSetMousePos(vector newPos)
{
    PlayerMouse = newPos;
}


function UpdateRotation(float DeltaTime, float maxPitch)
{

    local rotator newRotation, ViewRotation;
    local ROVehicle ROVeh;
    local KFHumanPawn ROPwn;
    local SmartAssaultRifle ROWeap;

	// Lets avoid casting 20 times every tick - Ramm
    ROPwn = KFHumanPawn(Pawn);
    if(Pawn != none)
    	ROWeap = SmartAssaultRifle(Pawn.Weapon);

    if( bSway && (Pawn != none)
         	  && Pawn.Weapon != none
		  && Pawn.Weapon.bCanSway)
    {
		MouseInterfaceSetRotationLock(false);
		SwayHandler(DeltaTime);
    }
    else
    {
        SwayYaw = 0.0;
        SwayPitch = 0.0;
        WeaponSwayYawRate = 0.0;
        WeaponSwayPitchRate = 0.0;
        SwayTime = 0.0;
    }


    if ( bInterpolating || ((Pawn != None) && Pawn.bInterpolating) )
    {
        ViewShake(deltaTime);
        return;
    }

    // Added FreeCam control for better view control
    if (bFreeCam == True)
    {
        if (bHudLocksPlayerRotation)
        {
            // No camera change if we're locking rotation
        }
	else if (bFreeCamZoom == True)
        {
            CameraDeltaRad += DeltaTime * 0.25 * aLookUp;
        }
        else if (bFreeCamSwivel == True)
        {
            CameraSwivel.Yaw += 16.0 * DeltaTime * aTurn;
            CameraSwivel.Pitch += 16.0 * DeltaTime * aLookUp;
        }
        else
        {
            CameraDeltaRotation.Yaw += 32.0 * DeltaTime * aTurn;
            CameraDeltaRotation.Pitch += 32.0 * DeltaTime * aLookUp;
        }
    }
    else
    {
	    ViewRotation = Rotation;

		if(Pawn != none && Pawn.Physics != PHYS_Flying) // mmmmm
		{
			// Ensure we are not setting the pawn to a rotation beyond its desired
			if(	Pawn.DesiredRotation.Roll < 65535 &&
				(ViewRotation.Roll < Pawn.DesiredRotation.Roll || ViewRotation.Roll > 0))
				ViewRotation.Roll = 0;
			else if( Pawn.DesiredRotation.Roll > 0 &&
				(ViewRotation.Roll > Pawn.DesiredRotation.Roll || ViewRotation.Roll < 65535))
				ViewRotation.Roll = 0;
		}

        DesiredRotation = ViewRotation; //save old rotation

        if ( bTurnToNearest != 0 )
            TurnTowardNearestEnemy();
        else if ( bTurn180 != 0 )
            TurnAround();
        else
        {
            TurnTarget = None;
            bRotateToDesired = false;
            bSetTurnRot = false;

            if (bHudLocksPlayerRotation)
            {
                // No camera change if we're locking rotation
            }
            else if( ROPwn!= none && ROPwn.bRestingWeapon )
            {
	           	ViewRotation.Yaw += 16.0 * DeltaTime * aTurn;
		       	ViewRotation.Pitch += 16.0 * DeltaTime * aLookUp;
            }
            else
            {
	           	ViewRotation.Yaw += 32.0 * DeltaTime * aTurn;
		       	ViewRotation.Pitch += 32.0 * DeltaTime * aLookUp;
	       	}

			if( (Pawn != none ) && (Pawn.Weapon != none) && (ROPwn != none))
			{
				ViewRotation = FreeAimHandler(ViewRotation, DeltaTime);
				//log ("FreeAimHandler is in use!!!!");
            }
        }

        if( ROPwn != none )
        	ViewRotation.Pitch = ROPwn.LimitPitch(ViewRotation.Pitch,DeltaTime); //amb

     //   if( (ROPwn != none)  )
	//	{
      //      ROPwn.LimitYaw(ViewRotation.Yaw);
      //  }

        // Limit Pitch and yaw for the ROVehicles - Ramm
        if ( Pawn != none )
        {
             if( Pawn.IsA('ROVehicle'))
             {
                  ROVeh = ROVehicle(Pawn);

                  ViewRotation.Yaw = ROVeh.LimitYaw(ViewRotation.Yaw);
                  ViewRotation.Pitch = ROVeh.LimitPawnPitch( ViewRotation.Pitch );
             }
        }

// TODO: Fix and Optimize this when the weapons are converted over
//        if(  bSway && (Pawn != none)
//              && (ROProjectileWeapon(Pawn.Weapon) != none)
//			  && ROProjectileWeapon(Pawn.Weapon).bUsingSights)
//        {
            ViewRotation.Yaw += SwayYaw;
            ViewRotation.Pitch += SwayPitch;
 //       }

		SetRotation(ViewRotation);

        ViewShake(deltaTime);
        ViewFlash(deltaTime);

		NewRotation = ViewRotation;

        NewRotation.Roll = Rotation.Roll;

        if ( (Pawn != None) && (!bBehindView) )
            Pawn.FaceRotation(NewRotation, deltatime);
    }
}


// Calculate the weapon sway
simulated function SwayHandler(float DeltaTime)
{
     local float WeaponSwayYawAcc;
     local float WeaponSwayPitchAcc;
     local float DeltaSwayYaw;
     local float DeltaSwayPitch;
     local float timeFactor;
     local float staminaFactor;
     local KFHumanPawn P;
     //local float zoomFactor;

	 P = KFHumanPawn(Pawn);

	 if (P == None )
		return;

  //   StaminaFactor = (P.default.Stamina - P.Stamina)/(P.default.Stamina*0.5);

     SwayTime += DeltaTime;

     if( SwayClearTime > 0.05 )
     {
 		SwayClearTime = 0.0;
		WeaponSwayYawAcc = RandRange( -baseSwayYawAcc, baseSwayYawAcc );
        WeaponSwayPitchAcc = RandRange( -baseSwayPitchAcc, baseSwayPitchAcc );
     }
     else
     {
		WeaponSwayYawAcc = 0.0;
        WeaponSwayPitchAcc = 0.0;
        SwayClearTime += DeltaTime;
     }

     timeFactor = InterpCurveEval(SwayCurve,SwayTime);

     // weapon acceleration (sway) is based on time in iron sights and
     // on lost stamina
     WeaponSwayYawAcc =  (timeFactor * WeaponSwayYawAcc) + (staminaFactor * WeaponSwayYawAcc);
     WeaponSwayPitchAcc =  (timeFactor * WeaponSwayPitchAcc) + (staminaFactor * WeaponSwayPitchAcc);

     // Sway reduction for crouching, prone, and resting the weapon
     if (P.bRestingWeapon)
     {
         WeaponSwayYawAcc *= 0.1;
         WeaponSwayPitchAcc *= 0.1;
     }
	 else if (P.bIsCrouched)
     {
         WeaponSwayYawAcc *= 0.5;
         WeaponSwayPitchAcc *= 0.5;
     }
     else if (P.bIsCrawling)
     {
         WeaponSwayYawAcc *= 0.15;
         WeaponSwayPitchAcc *= 0.15;
     }

 //    if( P.LeanAmount != 0)
  //   {
 //		 WeaponSwayYawAcc *= 1.45;
  //       WeaponSwayPitchAcc *= 1.45;
 //    }

     // added a elastic factor to get sway near the original aim-point
     // added a damping factor to keep the elastic factor from causing wild oscillations
     WeaponSwayYawAcc = WeaponSwayYawAcc - (SwayElasticFactor*SwayYaw) - (SwayDampingFactor*WeaponSwayYawRate);
     WeaponSwayPitchAcc = WeaponSwayPitchAcc - (SwayElasticFactor*SwayPitch) - (SwayDampingFactor*WeaponSwayPitchRate);

     // basic equation of motion (deltaX = vt + 1/2*a*t^2)
     DeltaSwayYaw = (WeaponSwayYawRate * DeltaTime) + (0.5*WeaponSwayYawAcc*DeltaTime*DeltaTime);
     DeltaSwayPitch = (WeaponSwayPitchRate * DeltaTime) + (0.5*WeaponSwayPitchAcc*DeltaTime*DeltaTime);
     SwayYaw += DeltaSwayYaw;
     SwayPitch += DeltaSwayPitch;

	 if (P.bRestingWeapon)
     {
         SwayYaw = 0;
         SwayPitch = 0;
     }

	// Maybe re-add this when we get the scoped weapons in
//    // Adjust by zoom factor of weapon
//    zoomFactor =0.65;//0.65*(DefaultFOV/ROWeapon(P.Weapon).ROPlayerFOVZoom);
//
//     // Sway reduction for crouching and prone - lets add this for snipers too!!! - Ramm
//	if (P.bIsCrouched)
//	{
//		FOVSwayYaw = 0.5*zoomFactor*(DeltaSwayYaw + SwayYawFraction);
//		FOVSwayPitch = 0.5*zoomFactor*(DeltaSwayPitch + SwayPitchFraction);
//	}
//	else if (P.bIsCrawling)
//	{
//		FOVSwayYaw = 0.35*zoomFactor*(DeltaSwayYaw + SwayYawFraction);
//		FOVSwayPitch = 0.35*zoomFactor*(DeltaSwayPitch + SwayPitchFraction);
//	}
//	else
//	{
//        FOVSwayYaw = zoomFactor*(DeltaSwayYaw + SwayYawFraction);
//        FOVSwayPitch = zoomFactor*(DeltaSwayPitch + SwayPitchFraction);
//    }

	// update new sway velocity
	WeaponSwayYawRate += WeaponSwayYawAcc*DeltaTime;
	WeaponSwayPitchRate += WeaponSwayPitchAcc*DeltaTime;
}

// Need to reset the sway when you switch stances so you don't retain the worse
// sway state when switching to a better sway state.
simulated function ResetSwayValues()
{
	WeaponSwayYawRate = 0;
	WeaponSwayPitchRate = 0;
}

//------------------------------------------------------------------------------
//	FreeAimHandler
// Calculate free-aim and process recoil
//------------------------------------------------------------------------------
simulated function rotator FreeAimHandler(rotator NewRotation, float DeltaTime)
{
	// try to move these to class variables so they aren't created every tick
	local rotator NewPlayerRotation;
    local int YawAdjust;
    local int PitchAdjust;
    local float	FreeAimBlendAmount;
    local rotator AppliedRecoil;

	if( Pawn == none || SmartAssaultRifle(Pawn.Weapon) == none ||
		!SmartAssaultRifle(Pawn.Weapon).ShouldUseFreeAim() )
	{
		LastFreeAimSuspendTime=Level.TimeSeconds;

		if( WeaponBufferRotation.Yaw != 0 )
		{
			if( WeaponBufferRotation.Yaw > 32768 )
			{
				WeaponBufferRotation.Yaw +=	YawTweenRate * deltatime;

				if( WeaponBufferRotation.Yaw > 65536 )
				{
					WeaponBufferRotation.Yaw = 0;
				}
			}
			else
			{
				WeaponBufferRotation.Yaw -=	YawTweenRate * deltatime;

				if( WeaponBufferRotation.Yaw <  0)
				{
					WeaponBufferRotation.Yaw = 0;
				}
			}
		}

		if( WeaponBufferRotation.Pitch != 0 )
		{
			if( WeaponBufferRotation.Pitch > 32768 )
			{
				WeaponBufferRotation.Pitch += PitchTweenRate * deltatime;

				if( WeaponBufferRotation.Pitch > 65536 )
				{
					WeaponBufferRotation.Pitch = 0;
				}
			}
			else
			{
				WeaponBufferRotation.Pitch -= PitchTweenRate * deltatime;

				if( WeaponBufferRotation.Pitch <  0)
				{
					WeaponBufferRotation.Pitch = 0;
				}
			}
		}

		// Process recoil
		// Handle recoil if the framerate is really low causing deltatime to be really high
/*		if( deltatime >= RecoilSpeed && ((Level.TimeSeconds - LastRecoilTime) <= (deltatime + (deltatime * 0.03))))
		{
			NewRotation += (RecoilRotator/RecoilSpeed) * deltatime/(deltatime/RecoilSpeed);
		}
		// Standard recoil
        else*/ if( Level.TimeSeconds - LastRecoilTime <= RecoilSpeed )
        {
			NewRotation += (RecoilRotator/RecoilSpeed) * deltatime;
        }
        else
        {
			RecoilRotator = rot(0,0,0);
        }

		return NewRotation;
	}

	NewPlayerRotation = NewRotation;

//	if( Level.TimeSeconds - LastFreeAimSuspendTime < 0.5 )
//	{
//		FreeAimBlendAmount = (Level.TimeSeconds - LastFreeAimSuspendTime)/0.5;
//	}
//	else
//	{
		FreeAimBlendAmount = 1;
//	}

	// Add the freeaim movement in
	if (!bHudLocksPlayerRotation)
	{
    	WeaponBufferRotation.Yaw += (FAAWeaponRotationFactor * DeltaTime * aTurn) * FreeAimBlendAmount;
    	WeaponBufferRotation.Pitch += (FAAWeaponRotationFactor * DeltaTime * aLookUp) * FreeAimBlendAmount;
    }


	// Process recoil
	// Handle recoil if the framerate is really low causing deltatime to be really high
/*	if( deltatime >= RecoilSpeed && ((Level.TimeSeconds - LastRecoilTime) <= (deltatime + (deltatime * 0.03))))
	{
	    AppliedRecoil = (RecoilRotator/RecoilSpeed) * deltatime/(deltatime/RecoilSpeed);
		WeaponBufferRotation += AppliedRecoil;
	}
	// standard recoil
    else*/ if( Level.TimeSeconds - LastRecoilTime <= RecoilSpeed )
    {
	    AppliedRecoil = (RecoilRotator/RecoilSpeed) * deltatime;
		WeaponBufferRotation += AppliedRecoil;
    }
    else
    {
		RecoilRotator = rot(0,0,0);
    }

	// Add recoil from a weapon that has been fired
	//WeaponBufferRotation += RecoilRotator;

	// Do the pitch and yaw limitation
    YawAdjust = WeaponBufferRotation.Yaw & 65535;

    if (YawAdjust > FreeAimMaxYawLimit && YawAdjust < FreeAimMinYawLimit)
    {
        if (YawAdjust - FreeAimMaxYawLimit < FreeAimMinYawLimit - YawAdjust)
            YawAdjust = FreeAimMaxYawLimit;
        else
            YawAdjust = FreeAimMinYawLimit;

       	NewPlayerRotation.Yaw += AppliedRecoil.Yaw;
    }

    WeaponBufferRotation.Yaw = YawAdjust;

    PitchAdjust = WeaponBufferRotation.Pitch & 65535;

    if (PitchAdjust > FreeAimMaxPitchLimit && PitchAdjust < FreeAimMinPitchLimit)
    {
        if (PitchAdjust - FreeAimMaxPitchLimit < FreeAimMinPitchLimit - PitchAdjust)
            PitchAdjust = FreeAimMaxPitchLimit;
        else
            PitchAdjust = FreeAimMinPitchLimit;

        NewPlayerRotation.Pitch += AppliedRecoil.Pitch;
    }

    WeaponBufferRotation.Pitch = PitchAdjust;

    //RecoilRotator = rot(0,0,0);

	return NewPlayerRotation;
}

simulated function MouseInterfaceSetRotationLock(bool bLocked)
{
    bHudLocksPlayerRotation = bLocked;
}

exec function ChangeCharacter(string newCharacter, optional string inClass)
{
	local ClientPerkRepLink S;

	S = Class'ClientPerkRepLink'.Static.FindStats(Self);

		SetPawnClass(string(PawnClass), newCharacter);

	if( S!=None )
		S.SelectedCharacter(newCharacter);

	else 
		Super.ChangeCharacter(newCharacter,inClass);
}



function SetPawnClass(string inClass, string inCharacter) {
    PawnClass = Class'AliensKFWeapons.AKFPawn'; // your pawn class here
    inCharacter = Class'KFGameType'.Static.GetValidCharacter(inCharacter);
    PawnSetupRecord = class'xUtil'.static.FindPlayerRecord(inCharacter);
    PlayerReplicationInfo.SetCharacterName(inCharacter);
}


defaultproperties
{
	PawnClass=Class'AliensKFWeapons.AKFPawn'
	InputClass=class'ROEngine.ROPlayerInput'
	// Free Aim variables
	FreeAimMaxYawLimit=2000
	FreeAimMinYawLimit=63535
	FreeAimMaxPitchLimit=1500
	FreeAimMinPitchLimit=64035
    YawTweenRate=8000
    PitchTweenRate=6000
	FAAWeaponRotationFactor = 8.0

    // Sway variables
	bSway = true
	baseSwayYawAcc = 100//150//75//1500.00
    baseSwayPitchAcc = 200//300//150//1500.00
    SwayCurve=(Points=((InVal=0.0,OutVal=0.0),(InVal=0.75,OutVal=0.1),(InVal=1.5,OutVal=0.25),(InVal=3.0,OutVal=0.5),(InVal=10.0,OutVal=1.0),(InVal=1000000000.0,OutVal=1.0)))
}
